package com.hunttown.common.domain;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.springframework.util.Assert;

public class Query extends HashMap implements Serializable {
    public static final String ORDER_BY_KEY = "orderBy";
    public static final String PN_KEY = "pn";
    public static final String PAGE_SIZE_KEY = "pageSize";
    public static final String START_KEY = "start";
    public static final String NEED_PAGE_KEY = "needPage";

    Query() {
        this.put("needPage", Boolean.FALSE);
    }

    Query(int pn, int pageSize) {
        if (pn < 1) {
            pn = 1;
        }

        if (pageSize < 5) {
            pageSize = 5;
        }

        if (pageSize > 10000) {
            pageSize = 10000;
        }

        int start = (pn - 1) * pageSize;
        this.put("pn", pn);
        this.put("pageSize", pageSize);
        this.put("start", start);
        this.put("needPage", this.isNeedPage());
    }

    public static Query page(int pn, int pageSize) {
        return new Query(pn, pageSize);
    }

    public static Query page(int pn) {
        return new Query(pn, 20);
    }

    public static Query noPage() {
        return new Query();
    }

    public <T extends Query> T addCondition(String key, Object value) {
        this.checkKey(key);
        this.put(key, value);
        return (T) this;
    }

    private void checkKey(String key) {
        Assert.notNull(key, "Query key can not is null");
        Assert.state(!"pn".equals(key), "Query pn please call Query.setPn(pn)");
        Assert.state(!"pageSize".equals(key), "Query pageSize please call Query.setPageSize(pageSize)");
        Assert.state(!"start".equals(key), "Query start is table first record location, please use another name");
        Assert.state(!"needPage".equals(key), "Query needPage to check whether need page");
        Assert.state(!"orderBy".equals(key), "Query _orders used to order by sort, please use another name");
    }

    private List<Order> getOrders() {
        List<Order> orders = (List) this.get("orderBy");
        if (orders == null) {
            orders = new ArrayList();
            this.put("orderBy", orders);
        }

        return (List) orders;
    }

    public <T extends Query> T descOrder(String property) {
        this.getOrders().add(Order.desc(property));
        this.computeOrderBy();
        return (T) this;
    }

    public <T extends Query> T ascOrder(String property) {
        this.getOrders().add(Order.asc(property));
        this.computeOrderBy();
        return (T) this;
    }

    public void computeOrderBy() {
        List<Order> orders = this.getOrders();
        if (orders != null && !orders.isEmpty()) {
            StringBuilder s = new StringBuilder(" order by ");
            boolean first = true;

            for (Iterator i$ = orders.iterator(); i$.hasNext(); first = false) {
                Order order = (Order) i$.next();
                if (!first) {
                    s.append(",");
                }

                s.append(order);
            }

            this.put("orderBy", s);
        } else {
            this.put("orderBy", "");
        }
    }

    public int getPn() {
        return ((Integer) this.get("pn")).intValue();
    }

    public int getPageSize() {
        return ((Integer) this.get("pageSize")).intValue();
    }

    public int getStart() {
        return ((Integer) this.get("start")).intValue();
    }

    public boolean isNeedPage() {
        return this.getStart() != -1;
    }

    public String toString() {
        return "Query{condition=" + new HashMap(this) + ", order=" + this.getOrders() + ", pn=" + this.getPn() + ", start=" + this.getStart() + ", pageSize=" + this.getPageSize() + '}';
    }
}